/**
*This software is under LGPL license,
*see http://www.gnu.org/licenses/lgpl-3.0.txt (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>)
*Console.h First issued by chuanshenglu@gmail.com 2008.10
*/
#include "Win32Console.h"

namespace TR{
	/**
	*Default constructor*/
	Win32Console::Win32Console(){
		mInputMode=INSERT;
		mTitle=TEXT("TR Console");
		//Handles to STD stuffs;
		mInputHandle=GetStdHandle(STD_INPUT_HANDLE);
		mOutputHandle=GetStdHandle(STD_OUTPUT_HANDLE);
		mErrorHandle=GetStdHandle(STD_ERROR_HANDLE);//this does not matter much!
		if(mInputHandle==NULL || mOutputHandle==NULL){
			cerr<<"Fail to get std handle,force quit."<<endl;
			exit(-1);
		}

		CONSOLE_SCREEN_BUFFER_INFO csbi;
		if(false==GetConsoleScreenBufferInfo(mOutputHandle,&csbi)){
			cerr<<"Failed to get screen buffer information."<<endl;
		}else{
			mSize.Y=csbi.dwSize.Y;
			mSize.X=csbi.dwSize.X;
			mCursorPos.X=csbi.dwCursorPosition.X;
			mCursorPos.Y=csbi.dwCursorPosition.Y;
			//For the GetConsoleWindow function does not work ;
			//so I have to force this;
			mSize.Y=25;
			SetConsoleScreenBufferSize(mOutputHandle,MakeCOORD(mSize.X,mSize.Y));
		}
		SetConsoleTitle(mTitle.c_str());
		SetConsoleTextAttribute(mOutputHandle,FOREGROUND_GREEN|FOREGROUND_INTENSITY);

		//SetConsoleDisplayMode(mOutputHandle,CONSOLE_FULLESCREEN_MODE,NULL);
		//Set cursor style;
		CONSOLE_CURSOR_INFO cci;
		cci.dwSize=100;
		cci.bVisible=TRUE;
		SetConsoleCursorInfo(mOutputHandle,&cci);
	}
	/**
	*Do clean and reset work;
	*/
	Win32Console::~Win32Console(){
	}

	/**
	*Enter main loop to dispatch messages;
	*/
	void Win32Console::EnterMainLoop(){
		INPUT_RECORD ir;
		DWORD NumberOfInputRead;
		while(TRUE){
			//Read one unit from the input buffer;
			ReadConsoleInput(mInputHandle,&ir,1,&NumberOfInputRead);
			if(ir.EventType==KEY_EVENT){
				OnKeyboardEvent(ir.Event.KeyEvent);
			}
			if(ir.EventType==FOCUS_EVENT){
			}
		}
	}
	/**
	*Process keyboard event
	*/
	void Win32Console::OnKeyboardEvent(KeyboardEvent e){
		if(mKeyboardListeners.empty()==true)
			return;
		for(Console::KeyboardListenerList::iterator itr=mKeyboardListeners.begin();
			itr!=mKeyboardListeners.end();itr++)
		{
			if(e.bKeyDown){
				//Keydown event;
				(*itr)->OnKeyDown(e);
			}else{
				//Keyup event;
				(*itr)->OnKeyUp(e);
			}
		}
	}

	/**
	*When the console window got focus or lost focus
	*/
	void Win32Console::OnFocusEvent(FocusEvent e){
		if(mFocusListeners.empty()==true)
			return;
		for(Console::FocusListenerList::iterator itr=mFocusListeners.begin();
			itr!=mFocusListeners.end();itr++)
		{
			if(e.bSetFocus){
				//Get focus;
				(*itr)->OnGetFocus();
			}else{
				(*itr)->OnLostFocus();
				//Lost focus;
			}
		}
	}

	/**Mov the output cursor to certain position*/
	BOOL Win32Console::MoveCursor(Coord pos){
		if(pos.X<mSize.X && pos.Y<mSize.Y){
			mCursorPos=pos;
			return SetConsoleCursorPosition(mOutputHandle,MakeCOORD(pos.X,pos.Y));
		}else
			return FALSE;
	}
	void Win32Console::ShowCursor(BOOL show){
		CONSOLE_CURSOR_INFO cci;
		cci.dwSize=100;
		cci.bVisible=show;
		SetConsoleCursorInfo(mOutputHandle,&cci);
	}

	/**Two very important methods of console;
	*Write a single character into the console*/	
	BOOL Win32Console::WriteChar(Coord pos,TCHAR ch){
		if(MoveCursor(pos)==TRUE){
			wcout<<ch;
			return TRUE;
		}else
			return FALSE;		
	}

	/**Try to write a line to specific position;
	*If the line is too long,ends at the right border of buffer and return FALSE,
	*else write the full line and return TRUE;*/	
	BOOL Win32Console::WriteLine(Coord _pos,const String& str){
		uint32 len=(uint32)str.length();
		if(len<(mSize.X-_pos.X)){
			for(uint32 i=0;i<len;++i,_pos.X++)
				WriteChar(_pos,str.at(i));
			return TRUE;
		}else{
			for(int i=0;_pos.X<mSize.X;_pos.X++,++i)
				WriteChar(_pos,str.at(i));
			return FALSE;
		}
	}

	//Get a char at certain position;
	TCHAR Win32Console::GetChar(Coord pos){
		return TCHAR(0);
	}

	//Set console Title;
	BOOL Win32Console::SetTitle(const String& str){
		mTitle=str;
		return SetConsoleTitle(mTitle.c_str());
	}
	BOOL Win32Console::SetTitle(const TCHAR* str){
		mTitle=str;
		return SetConsoleTitle(mTitle.c_str());
	}
}